package org.itest.jci.v2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;

/**
 * Java 代码编译执行
 */
public class CompilerRunBoostHandler {

    static String classGen = "public class [cname] implements java.util.concurrent.Callable<Object> {public Object call() throws Exception {[run]}}";

    static Object jarLauncher;
    static Object archives;
    static Method createClassLoader;
    private static final Logger LOGGER = LoggerFactory.getLogger(CompilerRunBoostHandler.class);

    static {
        try {
            jarLauncher = CompilerRunBoostHandler.class.getClassLoader().loadClass("org.springframework.boot.loader.JarLauncher").newInstance();
            Method getClassPathArchives = ReflectUtil.findMethod(jarLauncher.getClass(), "getClassPathArchives");
            getClassPathArchives.setAccessible(true);
            archives = getClassPathArchives.invoke(jarLauncher);
            createClassLoader = ReflectUtil.findMethod(jarLauncher.getClass(), "createClassLoader", List.class);
            createClassLoader.setAccessible(true);
        } catch (Exception e) {
            LOGGER.warn("CompilerRunBoostHandler init error!", e);
        }
    }

    public static ClassLoader createClassLoader() throws Exception {
        return (ClassLoader) createClassLoader.invoke(jarLauncher, archives);
    }

    public static Object compiler(String code) throws Exception {
        String cname = "RuntimeCompiler" + UUID.randomUUID().toString().replace("-","");
        URLClassLoader classLoader = (URLClassLoader) createClassLoader();
//        Class<?> aClass = classLoader.loadClass("top.wboost.common.utils.web.utils.PropertiesUtil");
//        System.out.println(aClass);
        String reduce = Arrays.stream(classLoader.getURLs()).map(URL::getFile).reduce((s1, s2) -> s1 + ";" + s2).orElse("error");
        System.out.println(reduce);
        String javaCode = classGen.replace("[cname]", cname)
                .replace("[run]", code);
        Class clz = CompilerUtils.CACHED_COMPILER.loadFromJava(createClassLoader(), cname, javaCode, CachedCompiler.DEFAULT_WRITER, Arrays.asList("-classpath", reduce,"-target","1.8"));
        Callable callable = (Callable) clz.newInstance();
        return callable.call();
    }

//    @Override
//    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response) {
//        Object ret = null;
//        try {
//            if (checkAccess(request)) {
//                String runcode = request.getParameter("runcode");
//                if (!StringUtils.isEmpty(runcode)) {
//                    ret = compiler(resolveCode(runcode));
//                } else {
//                    ret = "please use runcode parameter";
//                }
//            } else {
//                ret = "NO ACCESS";
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            ret = e.getMessage();
//        }
//
//        return null;
//    }



    public static void main(String[] args) {
        runcode();
    }

    public static void runcode() {
        String runcode = "String test = \"测试\";\n" +
                "            System.out.println(test);\n" +
                "            org.itest.jci.Test.test();\n"+
                "            return test;";
        try {
            compiler(runcode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}